1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package com.sun.tools.hat.internal.model;
34
35 import java.lang.ref.SoftReference;
36 import java.util.*;
37 import com.sun.tools.hat.internal.parser.ReadBuffer;
38 import com.sun.tools.hat.internal.util.Misc;
39
40
41
42
43
44
45
46
47
48
49
50
51 public class Snapshot {
52
53 public static long SMALL_ID_MASK = 0x0FFFFFFFFL;
54 public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
55
56 private static final JavaField[] EMPTY_FIELD_ARRAY = new JavaField[0];
57 private static final JavaStatic[] EMPTY_STATIC_ARRAY = new JavaStatic[0];
58
59
60 private Hashtable<Number, JavaHeapObject> heapObjects =
61 new Hashtable<Number, JavaHeapObject>();
62
63 private Hashtable<Number, JavaClass> fakeClasses =
64 new Hashtable<Number, JavaClass>();
65
66
67 private Vector<Root> roots = new Vector<Root>();
68
69
70 private Map<String, JavaClass> classes =
71 new TreeMap<String, JavaClass>();
72
73
74 private volatile Map<JavaHeapObject, Boolean> newObjects;
75
76
77 private volatile Map<JavaHeapObject, StackTrace> siteTraces;
78
79
80 private Map<JavaHeapObject, Root> rootsMap =
81 new HashMap<JavaHeapObject, Root>();
82
83
84 private SoftReference<Vector> finalizablesCache;
85
86
87 private JavaThing nullThing;
88
89
90 private JavaClass weakReferenceClass;
91
92 private int referentFieldIndex;
93
94
95 private JavaClass javaLangClass;
96
97 private JavaClass javaLangString;
98
99 private JavaClass javaLangClassLoader;
100
101
102 private volatile JavaClass otherArrayType;
103
104 private ReachableExcludes reachableExcludes;
105
106 private ReadBuffer readBuf;
107
108
109 private boolean hasNewSet;
110 private boolean unresolvedObjectsOK;
111
112
113
114 private boolean newStyleArrayClass;
115
116
117 private int identifierSize = 4;
118
119
120
121
122 private int minimumObjectSize;
123
124 public Snapshot(ReadBuffer buf) {
125 nullThing = new HackJavaValue("<null>", 0);
126 readBuf = buf;
127 }
128
129 public void setSiteTrace(JavaHeapObject obj, StackTrace trace) {
130 if (trace != null && trace.getFrames().length != 0) {
131 initSiteTraces();
132 siteTraces.put(obj, trace);
133 }
134 }
135
136 public StackTrace getSiteTrace(JavaHeapObject obj) {
137 if (siteTraces != null) {
138 return siteTraces.get(obj);
139 } else {
140 return null;
141 }
142 }
143
144 public void setNewStyleArrayClass(boolean value) {
145 newStyleArrayClass = value;
146 }
147
148 public boolean isNewStyleArrayClass() {
149 return newStyleArrayClass;
150 }
151
152 public void setIdentifierSize(int size) {
153 identifierSize = size;
154 minimumObjectSize = 2 * size;
155 }
156
157 public int getIdentifierSize() {
158 return identifierSize;
159 }
160
161 public int getMinimumObjectSize() {
162 return minimumObjectSize;
163 }
164
165 public void addHeapObject(long id, JavaHeapObject ho) {
166 heapObjects.put(makeId(id), ho);
167 }
168
169 public void addRoot(Root r) {
170 r.setIndex(roots.size());
171 roots.addElement(r);
172 }
173
174 public void addClass(long id, JavaClass c) {
175 addHeapObject(id, c);
176 putInClassesMap(c);
177 }
178
179 JavaClass addFakeInstanceClass(long classID, int instSize) {
180
181 String name = "unknown-class<@" + Misc.toHex(classID) + ">";
182
183
184
185
186 int numInts = instSize / 4;
187 int numBytes = instSize % 4;
188 JavaField[] fields = new JavaField[numInts + numBytes];
189 int i;
190 for (i = 0; i < numInts; i++) {
191 fields[i] = new JavaField("unknown-field-" + i, "I");
192 }
193 for (i = 0; i < numBytes; i++) {
194 fields[i + numInts] = new JavaField("unknown-field-" +
195 i + numInts, "B");
196 }
197
198
199 JavaClass c = new JavaClass(name, 0, 0, 0, 0, fields,
200 EMPTY_STATIC_ARRAY, instSize);
201
202 addFakeClass(makeId(classID), c);
203 return c;
204 }
205
206
207
208
209
210
211
212
213 public boolean getHasNewSet() {
214 return hasNewSet;
215 }
216
217
218
219
220 private static class MyVisitor extends AbstractJavaHeapObjectVisitor {
221 JavaHeapObject t;
222 public void visit(JavaHeapObject other) {
223 other.addReferenceFrom(t);
224 }
225 }
226
227
228 private static final int DOT_LIMIT = 5000;
229
230
231
232
233 public void resolve(boolean calculateRefs) {
234 System.out.println("Resolving " + heapObjects.size() + " objects...");
235
236
237
238
239 javaLangClass = findClass("java.lang.Class");
240 if (javaLangClass == null) {
241 System.out.println("WARNING: hprof file does not include java.lang.Class!");
242 javaLangClass = new JavaClass("java.lang.Class", 0, 0, 0, 0,
243 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
244 addFakeClass(javaLangClass);
245 }
246 javaLangString = findClass("java.lang.String");
247 if (javaLangString == null) {
248 System.out.println("WARNING: hprof file does not include java.lang.String!");
249 javaLangString = new JavaClass("java.lang.String", 0, 0, 0, 0,
250 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
251 addFakeClass(javaLangString);
252 }
253 javaLangClassLoader = findClass("java.lang.ClassLoader");
254 if (javaLangClassLoader == null) {
255 System.out.println("WARNING: hprof file does not include java.lang.ClassLoader!");
256 javaLangClassLoader = new JavaClass("java.lang.ClassLoader", 0, 0, 0, 0,
257 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
258 addFakeClass(javaLangClassLoader);
259 }
260
261 for (JavaHeapObject t : heapObjects.values()) {
262 if (t instanceof JavaClass) {
263 t.resolve(this);
264 }
265 }
266
267
268 for (JavaHeapObject t : heapObjects.values()) {
269 if (!(t instanceof JavaClass)) {
270 t.resolve(this);
271 }
272 }
273
274 heapObjects.putAll(fakeClasses);
275 fakeClasses.clear();
276
277 weakReferenceClass = findClass("java.lang.ref.Reference");
278 if (weakReferenceClass == null) {
279 weakReferenceClass = findClass("sun.misc.Ref");
280 referentFieldIndex = 0;
281 } else {
282 JavaField[] fields = weakReferenceClass.getFieldsForInstance();
283 for (int i = 0; i < fields.length; i++) {
284 if ("referent".equals(fields[i].getName())) {
285 referentFieldIndex = i;
286 break;
287 }
288 }
289 }
290
291 if (calculateRefs) {
292 calculateReferencesToObjects();
293 System.out.print("Eliminating duplicate references");
294 System.out.flush();
295
296 }
297 int count = 0;
298 for (JavaHeapObject t : heapObjects.values()) {
299 t.setupReferers();
300 ++count;
301 if (calculateRefs && count % DOT_LIMIT == 0) {
302 System.out.print(".");
303 System.out.flush();
304 }
305 }
306 if (calculateRefs) {
307 System.out.println("");
308 }
309
310
311
312 classes = Collections.unmodifiableMap(classes);
313 }
314
315 private void calculateReferencesToObjects() {
316 System.out.print("Chasing references, expect "
317 + (heapObjects.size() / DOT_LIMIT) + " dots");
318 System.out.flush();
319 int count = 0;
320 MyVisitor visitor = new MyVisitor();
321 for (JavaHeapObject t : heapObjects.values()) {
322 visitor.t = t;
323
324 t.visitReferencedObjects(visitor);
325 ++count;
326 if (count % DOT_LIMIT == 0) {
327 System.out.print(".");
328 System.out.flush();
329 }
330 }
331 System.out.println();
332 for (Root r : roots) {
333 r.resolve(this);
334 JavaHeapObject t = findThing(r.getId());
335 if (t != null) {
336 t.addReferenceFromRoot(r);
337 }
338 }
339 }
340
341 public void markNewRelativeTo(Snapshot baseline) {
342 hasNewSet = true;
343 for (JavaHeapObject t : heapObjects.values()) {
344 boolean isNew;
345 long thingID = t.getId();
346 if (thingID == 0L || thingID == -1L) {
347 isNew = false;
348 } else {
349 JavaThing other = baseline.findThing(t.getId());
350 if (other == null) {
351 isNew = true;
352 } else {
353 isNew = !t.isSameTypeAs(other);
354 }
355 }
356 t.setNew(isNew);
357 }
358 }
359
360 public Enumeration<JavaHeapObject> getThings() {
361 return heapObjects.elements();
362 }
363
364
365 public JavaHeapObject findThing(long id) {
366 Number idObj = makeId(id);
367 JavaHeapObject jho = heapObjects.get(idObj);
368 return jho != null? jho : fakeClasses.get(idObj);
369 }
370
371 public JavaHeapObject findThing(String id) {
372 return findThing(Misc.parseHex(id));
373 }
374
375 public JavaClass findClass(String name) {
376 if (name.startsWith("0x")) {
377 return (JavaClass) findThing(name);
378 } else {
379 return classes.get(name);
380 }
381 }
382
383
384
385
386 public Iterator getClasses() {
387
388
389 return classes.values().iterator();
390 }
391
392 public JavaClass[] getClassesArray() {
393 JavaClass[] res = new JavaClass[classes.size()];
394 classes.values().toArray(res);
395 return res;
396 }
397
398 public synchronized Enumeration getFinalizerObjects() {
399 Vector obj;
400 if (finalizablesCache != null &&
401 (obj = finalizablesCache.get()) != null) {
402 return obj.elements();
403 }
404
405 JavaClass clazz = findClass("java.lang.ref.Finalizer");
406 JavaObject queue = (JavaObject) clazz.getStaticField("queue");
407 JavaThing tmp = queue.getField("head");
408 Vector<JavaHeapObject> finalizables = new Vector<JavaHeapObject>();
409 if (tmp != getNullThing()) {
410 JavaObject head = (JavaObject) tmp;
411 while (true) {
412 JavaHeapObject referent = (JavaHeapObject) head.getField("referent");
413 JavaThing next = head.getField("next");
414 if (next == getNullThing() || next.equals(head)) {
415 break;
416 }
417 head = (JavaObject) next;
418 finalizables.add(referent);
419 }
420 }
421 finalizablesCache = new SoftReference<Vector>(finalizables);
422 return finalizables.elements();
423 }
424
425 public Enumeration<Root> getRoots() {
426 return roots.elements();
427 }
428
429 public Root[] getRootsArray() {
430 Root[] res = new Root[roots.size()];
431 roots.toArray(res);
432 return res;
433 }
434
435 public Root getRootAt(int i) {
436 return roots.elementAt(i);
437 }
438
439 public ReferenceChain[]
440 rootsetReferencesTo(JavaHeapObject target, boolean includeWeak) {
441 Vector<ReferenceChain> fifo = new Vector<ReferenceChain>();
442
443 Hashtable<JavaHeapObject, JavaHeapObject> visited = new Hashtable<JavaHeapObject, JavaHeapObject>();
444
445 Vector<ReferenceChain> result = new Vector<ReferenceChain>();
446 visited.put(target, target);
447 fifo.addElement(new ReferenceChain(target, null));
448
449 while (fifo.size() > 0) {
450 ReferenceChain chain = fifo.elementAt(0);
451 fifo.removeElementAt(0);
452 JavaHeapObject curr = chain.getObj();
453 if (curr.getRoot() != null) {
454 result.addElement(chain);
455
456
457 }
458 Enumeration referers = curr.getReferers();
459 while (referers.hasMoreElements()) {
460 JavaHeapObject t = (JavaHeapObject) referers.nextElement();
461 if (t != null && !visited.containsKey(t)) {
462 if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) {
463 visited.put(t, t);
464 fifo.addElement(new ReferenceChain(t, chain));
465 }
466 }
467 }
468 }
469
470 ReferenceChain[] realResult = new ReferenceChain[result.size()];
471 for (int i = 0; i < result.size(); i++) {
472 realResult[i] = result.elementAt(i);
473 }
474 return realResult;
475 }
476
477 public boolean getUnresolvedObjectsOK() {
478 return unresolvedObjectsOK;
479 }
480
481 public void setUnresolvedObjectsOK(boolean v) {
482 unresolvedObjectsOK = v;
483 }
484
485 public JavaClass getWeakReferenceClass() {
486 return weakReferenceClass;
487 }
488
489 public int getReferentFieldIndex() {
490 return referentFieldIndex;
491 }
492
493 public JavaThing getNullThing() {
494 return nullThing;
495 }
496
497 public void setReachableExcludes(ReachableExcludes e) {
498 reachableExcludes = e;
499 }
500
501 public ReachableExcludes getReachableExcludes() {
502 return reachableExcludes;
503 }
504
505
506 void addReferenceFromRoot(Root r, JavaHeapObject obj) {
507 Root root = rootsMap.get(obj);
508 if (root == null) {
509 rootsMap.put(obj, r);
510 } else {
511 rootsMap.put(obj, root.mostInteresting(r));
512 }
513 }
514
515 Root getRoot(JavaHeapObject obj) {
516 return rootsMap.get(obj);
517 }
518
519 JavaClass getJavaLangClass() {
520 return javaLangClass;
521 }
522
523 JavaClass getJavaLangString() {
524 return javaLangString;
525 }
526
527 JavaClass getJavaLangClassLoader() {
528 return javaLangClassLoader;
529 }
530
531 JavaClass getOtherArrayType() {
532 if (otherArrayType == null) {
533 synchronized(this) {
534 if (otherArrayType == null) {
535 addFakeClass(new JavaClass("[<other>", 0, 0, 0, 0,
536 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY,
537 0));
538 otherArrayType = findClass("[<other>");
539 }
540 }
541 }
542 return otherArrayType;
543 }
544
545 JavaClass getArrayClass(String elementSignature) {
546 JavaClass clazz;
547 synchronized(classes) {
548 clazz = findClass("[" + elementSignature);
549 if (clazz == null) {
550 clazz = new JavaClass("[" + elementSignature, 0, 0, 0, 0,
551 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
552 addFakeClass(clazz);
553
554
555
556
557 }
558 }
559 return clazz;
560 }
561
562 ReadBuffer getReadBuffer() {
563 return readBuf;
564 }
565
566 void setNew(JavaHeapObject obj, boolean isNew) {
567 initNewObjects();
568 if (isNew) {
569 newObjects.put(obj, Boolean.TRUE);
570 }
571 }
572
573 boolean isNew(JavaHeapObject obj) {
574 if (newObjects != null) {
575 return newObjects.get(obj) != null;
576 } else {
577 return false;
578 }
579 }
580
581
582 private Number makeId(long id) {
583 if (identifierSize == 4) {
584 return new Integer((int)id);
585 } else {
586 return new Long(id);
587 }
588 }
589
590 private void putInClassesMap(JavaClass c) {
591 String name = c.getName();
592 if (classes.containsKey(name)) {
593
594
595
596 name += "-" + c.getIdString();
597 }
598 classes.put(c.getName(), c);
599 }
600
601 private void addFakeClass(JavaClass c) {
602 putInClassesMap(c);
603 c.resolve(this);
604 }
605
606 private void addFakeClass(Number id, JavaClass c) {
607 fakeClasses.put(id, c);
608 addFakeClass(c);
609 }
610
611 private synchronized void initNewObjects() {
612 if (newObjects == null) {
613 synchronized (this) {
614 if (newObjects == null) {
615 newObjects = new HashMap<JavaHeapObject, Boolean>();
616 }
617 }
618 }
619 }
620
621 private synchronized void initSiteTraces() {
622 if (siteTraces == null) {
623 synchronized (this) {
624 if (siteTraces == null) {
625 siteTraces = new HashMap<JavaHeapObject, StackTrace>();
626 }
627 }
628 }
629 }
630 }